package Game;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.io.File;
import java.io.Serializable;

import javax.imageio.ImageIO;
import javax.swing.*;

import GUIInterfaces.OregonPanel;
import GUIInterfaces.OregonWindow;

import java.util.*;

/*
 * @author William Kurkian
 * This is the map. Treat it as an OregonPanel. Note that it is important to update the game driver after doing any actions in other panels.
 */
public class MapPanel extends JPanel implements MouseMotionListener,MouseListener, OregonPanel, ActionListener, Serializable {

	OregonWindow parent;
	GameDriver gd;
	BufferedImage background;
	Caravan caravan;
	ArrayList<Rectangle> locationsClick = new ArrayList<Rectangle>();
	ArrayList<Integer> locations = new ArrayList<Integer>();
	double x,y;
	BufferedImage cart;
	
	JButton actions = new JButton();
	JButton save = new JButton();
	int currentLocation = 0;
	int nextLocation = 0;
	int lastLoc = 0;
	int hoveredOver = -1;
	boolean riverCrossing;
	//property for oregonpannel. Here it ndicates the exit state.
	private String property = "";
	/*
	 * Initializes to the initial values specified by GPS.
	 */
	public MapPanel(OregonWindow parent, GameDriver gd) {
		this.gd = gd;
		this.parent = parent;
		caravan = gd.getCaravan();
		addMouseListener(this);
		addMouseMotionListener(this);
		setLayout(null);
		
		configureButton(actions,new Rectangle(844,613,120,110));
		configureButton(save,new Rectangle(48,18,76,82));
		add(actions);
		add(save);
		
		currentLocation = caravan.getCaravanGPS().currentLocation;
		nextLocation = caravan.getCaravanGPS().nextLocation;
		refreshLocations();
		x = GameDriver.getLocationList().getXPosistion(currentLocation);
		y = GameDriver.getLocationList().getYPosistion(currentLocation);
		update(-1);
		String folder = System.getProperty("user.dir")+ File.separator + "images" + File.separator;
		try {
			background = ImageIO.read(new File(folder+"map.png"));
			cart = ImageIO.read(new File(folder+"movecart1.png"));
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, "Could not load map image.");
			
		}
		repaint();
	}
	
	/**
	 * Method to configure buttons. It makes them invisible and sets their bounds to rectangle.
	 * @param button
	 * @param rectangle
	 */
	private void configureButton(JButton button, Rectangle rectangle) {
		button.setBounds(rectangle);
		button.setOpaque(false);
		button.setContentAreaFilled(false);
		button.setBorderPainted(false);
		button.addActionListener(this);
		
	}

	/**
	 * This method configures the passed in label.
	 * @param label
	 * @param rectangle
	 */
	private void configureLabel(JLabel label, Rectangle rectangle) {
		label.setBounds(rectangle);
		label.setFont(new Font(label.getFont().getName(), label.getFont().getStyle(),20));
	}
	
	@Override
	/*
	 * (non-Javadoc)
	 * @see OregonPanel#getGameDriver()
	 */
	public GameDriver getGameDriver() {
		return gd;
	}
	/**
	 * `Resets the map panel to the gps when game is reset.
	 */
	public void reset() {
		currentLocation = 0;
		refreshLocations();
		x = GameDriver.getLocationList().getXPosistion(currentLocation);
		y = GameDriver.getLocationList().getYPosistion(currentLocation);
		
		repaint();
	}
	@Override
	/**
	 * The mouseCLicked method compares the position of the mouse with thoes of the rectangles, and if any rectangles contain it, then it is time to move to a 
	 * city. Currently it only allows forward motion.
	 */
	public void mouseClicked(MouseEvent arg0) {
		for (int i = 0; i < locationsClick.size(); i++) {
			Rectangle location = locationsClick.get(i);
			if (location.contains(arg0.getPoint())) {
					update(i);
			}
		}
	}
	
	public void update(int i) {
		GPS gps = caravan.getCaravanGPS();
		int dest;
		if ( i == -2) 
			dest = nextLocation;
		else if ( i != -1)
			dest = locations.get(i);
		else 
			dest = nextLocation;
		if (gd.getLocationList().isBridge(gps.currentLocation) && !gps.traveling && dest != lastLoc && i != -2) {
			Object[] possibilities = {"River crossing game (free but risky)", "Pay the toll to cross.(no risk)", "Ford it somewhere(Free but risky)"};
			String s = (String)JOptionPane.showInputDialog(
			                    this,
			                    "How would you like to cross the river?",
			                    "River crossing",
			                    JOptionPane.PLAIN_MESSAGE,
			                    null,
			                    possibilities,
			                    possibilities[0]);
			if (s.equals(possibilities[0])) {
				property = "river";
				nextLocation = dest;
				parent.done(this);
				return;
			} else if (s.equals(possibilities[1])) {
				Caravan car = gd.getCaravan();
				int toll = 20;
				if (car.getPlayerMoney() >= toll) {
					car.setPlayerMoney(car.getPlayerMoney()-toll);
				} else{
					JOptionPane.showMessageDialog(this,"You need " + toll + " to cross. You only have " + car.getPlayerMoney() + ".");
					return;
				}
				gd.setCaravan(car);
					
			} else if (s.equals(possibilities[2])) {
				double ch = Math.random();
				if (ch > 0.20) {
					JOptionPane.showMessageDialog(this,"You crossed successfully.");
				} else {
					JOptionPane.showMessageDialog(this,"Your vehicle got washed away. You retrieved it but you lost 50 pesos.");
					Caravan car = gd.getCaravan();
					if (car.getPlayerMoney() > 50) {
						car.setPlayerMoney(car.getPlayerMoney()-50);
					} else
						car.setPlayerMoney(0);
					gd.setCaravan(car);
				}
			}
		}
		
		if (i != -1)
			gps.setNextLocation(dest, (int)(gd.getPace().getMulti()*30));
		
		if (gps.nextLocation != gps.currentLocation) {
			currentLocation = gps.currentLocation;
			nextLocation = gps.nextLocation;
		}
		
		caravan.setCaravanGPS(gps);
		if (gps.traveling) {
			locations.clear();
			locationsClick.clear();
			locations.add(nextLocation);
			locations.add(currentLocation);
			
			if (gps.currentLocation == gps.nextLocation) {
				int steps = (int)((gps.totalDistanceToNextLocation-gps.distanceToNextLocation)/(gd.getPace().getMulti()*30));
				double deltax = GameDriver.getLocationList().getXPosistion(currentLocation) - GameDriver.getLocationList().getXPosistion(nextLocation);
				double deltay = GameDriver.getLocationList().getYPosistion(currentLocation) - GameDriver.getLocationList().getYPosistion(nextLocation);
				locationsClick.add(new Rectangle(GameDriver.getLocationList().getXPosistion(nextLocation)-10,GameDriver.getLocationList().getYPosistion(nextLocation)-10,20,20));
				locationsClick.add(new Rectangle(GameDriver.getLocationList().getXPosistion(currentLocation)-10,GameDriver.getLocationList().getYPosistion(currentLocation)-10,20,20));
				x= GameDriver.getLocationList().getXPosistion(nextLocation) + (deltax*((gd.getPace().getMulti()*30)/(double)gps.totalDistanceToNextLocation))*steps;
				y= GameDriver.getLocationList().getYPosistion(nextLocation) + (deltay*((gd.getPace().getMulti()*30)/(double)gps.totalDistanceToNextLocation))*steps;
				
			} else {
				int steps = (int)((gps.totalDistanceToNextLocation-gps.distanceToNextLocation)/(gd.getPace().getMulti()*30));
				double deltax = GameDriver.getLocationList().getXPosistion(nextLocation) - GameDriver.getLocationList().getXPosistion(currentLocation);
				double deltay = GameDriver.getLocationList().getYPosistion(nextLocation) - GameDriver.getLocationList().getYPosistion(currentLocation);
				locationsClick.add(new Rectangle(GameDriver.getLocationList().getXPosistion(nextLocation)-10,GameDriver.getLocationList().getYPosistion(nextLocation)-10,20,20));
				locationsClick.add(new Rectangle(GameDriver.getLocationList().getXPosistion(currentLocation)-10,GameDriver.getLocationList().getYPosistion(currentLocation)-10,20,20));
				x= GameDriver.getLocationList().getXPosistion(currentLocation) + (deltax*((gd.getPace().getMulti()*30)/(double)gps.totalDistanceToNextLocation))*steps;
				y= GameDriver.getLocationList().getYPosistion(currentLocation) + (deltay*((gd.getPace().getMulti()*30)/(double)gps.totalDistanceToNextLocation))*steps;
				
			}
			
			gd.setCaravan(caravan);
			gd.takeTurn();
			if (gd.message != null) {
				JOptionPane.showMessageDialog(this, gd.message);
			}
			boolean allDead = true;;
			for (Character c : gd.getCaravan().getCharacters()) {
				if (c.isAlive()) {
					allDead = false;
				}
			}
			if (allDead) {
				JOptionPane.showMessageDialog(this, "Everyone has died. You lose.");
				System.exit(1);
			}
			caravan = gd.getCaravan();
			repaint();
		} else {
			lastLoc = currentLocation;
			currentLocation = gps.currentLocation;
			refreshLocations();
			x = GameDriver.getLocationList().getXPosistion(currentLocation);
			y = GameDriver.getLocationList().getYPosistion(currentLocation);
			
			repaint();
		}
			

	}
	
	/**
	 * Refreshes the list of rectangles according to the surrounding locations of the current city.
	 */
	private void refreshLocations() {
		locations.clear();
		locationsClick.clear();
		hoveredOver = -1;
		ArrayList<HashMap<String,Integer>> nextLocations = GameDriver.getLocationList().getSurroundingLocations(currentLocation);
		for (HashMap<String,Integer> location : nextLocations) {
			int id = location.get("id");
			locations.add(id);
			locationsClick.add(new Rectangle(GameDriver.getLocationList().getXPosistion(id)-10,GameDriver.getLocationList().getYPosistion(id)-10,20,20));
			
		}
		
	}
	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}
	/**
	 * Paints the images.
	 */
	public void paintComponent(Graphics g) {
		g.drawImage(background, 0, 0, null);
		g.setColor(Color.BLUE);
		for (Rectangle location : locationsClick) {
			g.fillOval(location.x, location.y, location.width, location.height);
		}
		if (hoveredOver != -1 && hoveredOver < locationsClick.size()) {
			g.setColor(Color.red);
			g.fillOval(locationsClick.get(hoveredOver).x, locationsClick.get(hoveredOver).y, locationsClick.get(hoveredOver).width, locationsClick.get(hoveredOver).height);
		}
		g.drawImage(cart, (int)x-15, (int)y-7, null);
		g.drawString("Distance: " + caravan.getCaravanGPS().getDistanceTraveled(), 190, 430);
		g.drawString("Food: " + caravan.getPlayerInventory().getRemainingFood(),190,450);
	}

	@Override
	/**
	 * Checks if settle or stpr have been clicked.
	 * Does the corresponding actions.
	 */
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		if (arg0.getSource() == actions) {
			property = "actions";
			parent.done(this);
		} else if (arg0.getSource() == save) {
			GameSave gs = new GameSave();
			String message = gs.saveGame(gd);
			JOptionPane.showMessageDialog(this, message);
		}
	}

	@Override
	/**
	 * Sets the game driver to the paramerter.
	 * Part of OregpnWindow.
	 */
	public void setGameDriver(GameDriver gd) {
		// TODO Auto-generated method stub
		this.gd = gd;
		caravan = gd.getCaravan();
	}

	@Override
	public void mouseDragged(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	/**
	 * Checks if any cities are hovered over and updates the map to show this.
	 */
	public void mouseMoved(MouseEvent arg0) {
		for (int i = 0; i < locationsClick.size(); i++) {
			Rectangle location = locationsClick.get(i);
			if (location.contains(arg0.getPoint())) {
				hoveredOver = i;
				repaint();
				return;
			}
		}
		hoveredOver = -1;
		repaint();
	}

	@Override
	/*
	 * (non-Javadoc)
	 * @see OregonPanel#getProperty()
	 */
	public String getProperty() {
		// TODO Auto-generated method stub
		return property;
	}
	
}
